package hasthi.actuators;

import hasthi.actuators.actions.ActionCallback;
import hasthi.common.HasthiException;
import hasthi.common.HasthiException.FaultCode;
import hasthi.common.constants.HasthiConstants;
import hasthi.config.ResourceProfile;
import hasthi.decision.Enviorment;
import hasthi.metamodel.resource.ManagedResource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;

import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SystemActionsScheduler implements ActionCenter {
    private static Log log = LogFactory.getLog(HasthiConstants.LOGGER_NAME);
    private boolean planning = true;
    
    private List<String> overloadedServices = new Vector<String>();
    private List<String> overloadedServiceHosts = new Vector<String>();
    protected List<ManagementAction> actions = new ArrayList<ManagementAction>();

    protected ActionContext actionContext;
    
    private Enviorment enviorment = new Enviorment();
    protected Map<String,Object> map = new ConcurrentHashMap<String, Object>();
    
    /**
     * This is a scheduler that scedule jobs using fixed size thread pool. It makes sure  if a thread get in a deadlock it is killed eventually
     */
     
    private int actionWorkerCount = 10;
    private long actionCount = 0;
    
    public SystemActionsScheduler(){
    }
    
    public void init(ActionContext actionContextparam) throws HasthiException {
        this.actionContext = actionContextparam;
        //map.put("SystemFailed",new Long(System.currentTimeMillis()));
    }

    public void signal(String signal,String... properties){
        //System.out.println("Signal:"+signal + Arrays.toString(properties));
    }
    
    public void invoke(ManagedResource resource, String operation, String soapAcion,String... parameters) throws HasthiException{
        String[][] actualParameters = new String[parameters.length][];
        for(int i=0;i<actualParameters.length;i++){
            actualParameters[i] = parameters[i].split("=");
        }
        CallOpAction callOpAction = new CallOpAction(resource,operation,actualParameters,soapAcion);
        invoke(callOpAction);
    }
    
    public void setProperty(ManagedResource resource,String name,String value) throws HasthiException{
        SetPropertyAction setValAction = new SetPropertyAction(resource,name,value);
        invoke(setValAction);
    }
    
    public List<String> getOverloadedServices() {
        return overloadedServices;
    }
    
    public List<String> getOverloadedServiceHosts() {
        return overloadedServiceHosts;
    }

    public void createService(String serviceName) throws HasthiException{
        SystemConfig systemConfig = actionContext.getSystemConfig();
        ResourceProfile resourceConfig = systemConfig.getResourceProfile(QName.valueOf(serviceName));
        if(resourceConfig != null){
            CreateServiceAction action = new CreateServiceAction(resourceConfig);
            invoke(action);    
        }else{
            throw new HasthiException("Resource profile for "+ serviceName + " not found",FaultCode.ConfigError);
        }
        
    }

    public void invoke(ManagementAction action) throws HasthiException {
        action.init(actionContext);
        if(planning){
            actions.add(action);
        }else{
            action.execute();
        }
        actionCount++;
        log.info(new StringBuffer().append("ActionScheduler[").append(actionCount).append("]").append(action.toString()).toString());
    }
    
    public void invoke(ManagementAction action, ActionCallback callback) throws HasthiException {
        action.setCallback(callback);
        invoke(action);
    }

    /**
     * This method plans the actions using a planner and submit them to a scheduler to to execution. May be we need to
     * remove the planning step out as well to make sure they do not slow down the main control loops
     */
    public void planAndExecuate() throws HasthiException{
        List<ManagementAction> plannedActions = actionContext.getPlanner().planActions(actions);
        //System.out.println("Actions "+plannedActions);
        for(ManagementAction action:plannedActions){
            actionContext.getScheduler().submit(action);    
        }
        actions.clear();
    }
    
    public void setPlanning(boolean planning) {
        this.planning = planning;
    }
    
    public ActionContext getActionContext() {
        return actionContext;
    }

    public Enviorment getEnviorment() {
        return enviorment;
    }
    
    
    public Object get(String key) {
        return map.get(key);
    }

    public Object put(String key, Object value) {
        return map.put(key, value);
    }
    
    public void remove(String key){
        map.remove(key);
    }
    
}
